#ifndef _EPOLL_SERVER_H_
#define _EPOLL_SERVER_H_

#include <iostream>
#include <assert.h>
#include <functional>
#include <sys/time.h>
#include "sock.hpp"
#include "epoll.hpp"

using namespace std;
// 实现epoll读取
class EpolltServer
{
    using func_t = function<void(string)>;

public:
    static const int default_port = 8080;
    static const int g_num = 64;

public:
    EpolltServer(func_t handler_request, const uint16_t &port = default_port)
        : _port(port), _revs_num(g_num), _handler_request(handler_request)
    {
        // 申请空间
        _revs = new struct epoll_event[_revs_num];
        // 创建listensock
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        // 创建epoll模型
        _epfd = Epoll::CreateEpoll();

        logMessage(DEBUG, "init success, listensock: %d, epfd: %d",
                   _listensock, _epfd);
        // 将_listensock先添加到epoll中，让epoll管理起来
        if (Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, _listensock, EPOLLIN)) // 添加成功
            logMessage(DEBUG, "add listensock to epoll success");
        else
            exit(6);
    }

    void Accepter(int listensock)
    {
        string clientip;
        uint16_t clientport;
        int sock = Sock::Accpet(listensock, &clientip, &clientport);
        if (sock < 0)
        {
            logMessage(WARNING, "accept error...");
            return;
        }
        // 不能直接读取，不知道底层有没有数据
        if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, sock, EPOLLIN)) // 添加失败
            return;
        logMessage(DEBUG, "add new sock: %d to epoll success.", sock);
    }

    void Recver(int sock)
    {
        // 读数据
        char buff[10240];
        ssize_t n = recv(sock, buff, sizeof(buff) - 1, 0);
        if (n > 0)
        {
            // 假设这里就是读到了一个完整的报文，目前无法保证（如解决粘包、序列化、反序列化）
            buff[n] = 0;
            _handler_request(buff); // 处理数据
        }
        else if (n == 0)
        {
            logMessage(NORMAL, "client: %d quit ,me too...", sock);
            // 一定先去掉epoll对sock的关心
            bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, 0);
            assert(res);
            (void)res;
            // close
            close(sock);
            logMessage(NORMAL, "client recv %d error, close error sock.", sock);
        }
    }
    void HandlerEvents(int n)
    {
        assert(n > 0);
        for (int i = 0; i < n; i++)
        {
            uint32_t revents = _revs[i].events;
            int sock = _revs[i].data.fd;
            if (revents & EPOLLIN) // 读事件就绪
            {
                // listensock就绪
                if (sock == _listensock)
                    Accepter(_listensock);
                // 普通sock就绪
                else
                    Recver(sock);
            }

            // if(revents &EPOLLOUT);//写事件
        }
    }

    void loopOnce(int timeout)
    {
        int n = Epoll::WaitEpoll(_epfd, _revs, _revs_num, timeout);
        switch (n)
        {
        case 0:
            logMessage(DEBUG, "timeout...");
            break;
        case -1:
            logMessage(WARNING, "epoll wait error: %s", strerror(errno));
            break;
        default:
            logMessage(DEBUG, "wait success......");
            HandlerEvents(n);
            break;
        }
    }

    void Start()
    {
        int timeout = -1;
        while (true)
        {
            loopOnce(timeout);
        }
    }

    ~EpolltServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_epfd >= 0)
            close(_epfd);
        if (_revs)
            delete[] _revs;
    }

private:
    int _listensock;
    int _epfd;
    uint16_t _port;
    struct epoll_event *_revs; // 已就绪资源
    int _revs_num;
    func_t _handler_request;
};

#endif